`timescale 1ns / 1ns
`define	DATA_WIDTH	256
`define n_256r1 256'hFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
`define n_sm2 256'hFFFFFFFE_FFFFFFFF_FFFFFFFF_FFFFFFFF_7203DF6B_21C6052B_53BBF409_39D54123


module verify_sign(input clk,
				   input rst_n,
				   input curve_sel,
				   input enable,
				   //output reg end_flag,
				   //output reg [14:0] state,
				   //output reg [14:0] next_state,
				   output reg [13:0] state,
				   output reg [13:0] next_state,

				   input [`DATA_WIDTH-1:0] s,
				   input [`DATA_WIDTH-1:0] r,
				   
				   //output reg bingo,
				   
				   input Hv_done,
				   input [`DATA_WIDTH-1:0] Hv_r,

				   /*
				   input sha512_done,
				   input sm3_done,
				   input [`DATA_WIDTH-1:0] sm3_r,
				   */

				   input ML_end_flag,
				   output reg ML_enable,
				   
				   input INV_end_flag,
				   output reg INV_enable,
				   output reg [1:0] I_sel,
				   
				   input MM_end_flag,
				   output MM_enable,
				   output func,
				   
				   output reg [21:0] r_sel,
				   output reg [7:0] M_sel_a,
				   output reg [7:0] M_sel_b,
				   output reg [7:0] A_sel_a,
				   output reg [7:0] A_sel_b, 
				   
				   input [`DATA_WIDTH-1:0] t1,//e
				   input [`DATA_WIDTH-1:0] t3,//u
				   input [`DATA_WIDTH-1:0] t4,
				   input [`DATA_WIDTH-1:0] t5,
				   input [`DATA_WIDTH-1:0] t7,
				   
				   output reg [`DATA_WIDTH-1:0] sm3_e,
				   output reg [`DATA_WIDTH-1:0] k1,//连接标量乘的k,存kg_x,
				   output reg [`DATA_WIDTH-1:0] k2,//连接标量乘的k
				   output reg [`DATA_WIDTH-1:0] kg_y,
				   output reg checkRr_no
				  );

reg end_flag;

wire [`DATA_WIDTH-1:0] n;
				      
wire [19:0] state_zaddu;

reg [7:0] count1,count2;

wire [`DATA_WIDTH-1:0] kk1,kk4;

//wire [`DATA_WIDTH+1:0] kk2,kk3,kk5,kk6;

wire [`DATA_WIDTH+1:0] kk2,kk5;

wire [`DATA_WIDTH:0] kk3,kk6;

wire ZADDU_end_flag;

reg ZADDU_enable;

wire [21:0] zaddu_r_sel;

wire [7:0] zaddu_M_sel_a,zaddu_M_sel_b,zaddu_A_sel_a,zaddu_A_sel_b;

wire [1:0] zaddu_I_sel;

wire [`DATA_WIDTH-1:0] rr;

reg Hv_done_f;

//reg sha512_done_f;

//reg sm3_done_f;

parameter IDLE    = 14'b00_0000_0000_0001,
		  CHECK_r = 14'b00_0000_0000_0010,
		  CHECK_s = 14'b00_0000_0000_0100,
		  SHA     = 14'b00_0000_0000_1000,
		  SM3     = 14'b00_0000_0000_1001,
		  ADD_T   = 14'b00_0000_0000_1010,
		  CHECK_T = 14'b00_0000_0000_1100,
		  INV     = 14'b00_0000_0001_0000,
		  MUL1    = 14'b00_0000_0010_0000,
		  MUL2    = 14'b00_0000_0100_0000,
		  KG      = 14'b00_0000_1000_0000,
		  KP      = 14'b00_0001_0000_0000,
		  EXCH    = 14'b00_0010_0000_0000,
		  ZADDU   = 14'b00_0100_0000_0000,
		  ADD_R   = 14'b00_0100_0000_0001,
		  CHECK_P = 14'b00_1000_0000_0000,
		  CALUR   = 14'b01_0000_0000_0000,
		  CHECKRr = 14'b10_0000_0000_0000;
		  //FINAL   = 15'b100_0000_0000_0000;
		  
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		state <= IDLE;
	end
	else
	begin
		state <= next_state;
	end
end

always @(*)
begin
	case(state)
		IDLE   :if(enable)
					next_state = CHECK_r;
				else
					next_state = IDLE;
		CHECK_r:if((r>=1)&&(r<=n)) 
					next_state = CHECK_s;
				else
					next_state = IDLE;
		CHECK_s:if(curve_sel == 1'b0)
					if((s>=1)&&(s<=n))
						next_state = SHA;
					else
						next_state = IDLE;
				else
					if((s>=1)&&(s<=n))
						next_state = SM3;
					else
						next_state = IDLE;
		SHA	   : if(Hv_done_f)
					next_state = INV;
				 else
					next_state = SHA;
		SM3    : if(Hv_done_f)
					next_state = ADD_T;
				 else
					next_state = SM3;
		ADD_T  : 	next_state = CHECK_T;
		CHECK_T: if(t1 != 256'h0)
					next_state = KG;
				 else
					next_state = IDLE;
		INV    : if(INV_end_flag)
					next_state =MUL1;
				 else
					next_state = INV;
		MUL1   : if(count1 == 10'd0)
					next_state = MUL2;
				 else
					next_state = MUL1;
		MUL2   : if(count2 == 10'd0)
					next_state = KG;
				 else
					next_state = MUL2;
		KG     : if(ML_end_flag)
					next_state = KP;
				 else
					next_state = KG;
		KP     : if(ML_end_flag)
					next_state = EXCH;
				 else
					next_state = KP;
		EXCH   : 	next_state = ZADDU;
		ZADDU  : if(curve_sel == 1'b0)
					if(ZADDU_end_flag)
						next_state = CHECK_P;
					else
						next_state = ZADDU;
				 else
					if(ZADDU_end_flag)
						next_state = ADD_R;
					else
						next_state = ZADDU;
		ADD_R  : next_state = CHECKRr;
		CHECK_P: if((t4==0) && (t5==0))
					next_state = IDLE;
				 else
					next_state = CALUR;
		CALUR  : 	next_state = CHECKRr;
		/*CHECKRr: if(curve_sel == 1'b0)
					 if(rr == r)
						next_state = FINAL;
					 else
						next_state = IDLE;
				 else
					 if(t4 == r)
						next_state = FINAL;
					 else
						next_state = IDLE;
		*/
		CHECKRr:	next_state = IDLE;
		//FINAL  :	next_state = IDLE;
		default : 	next_state = IDLE;
	endcase
end

/*
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		checkRr_no <= 1'b0;
	else if(state == CHECKRr)
		if(curve_sel == 1'b0)
			if(rr != r)
				checkRr_no <= 1'b1;
			else
				checkRr_no <= 1'b0;
		else 
			if(t4 != r)
				checkRr_no <= 1'b1;
			else
				checkRr_no <= 1'b0;
	else
		checkRr_no <= 1'b0;
end
*/
always @(*)
begin
	if(state == CHECKRr)
		if(curve_sel == 1'b0)
			if(rr != r)
				checkRr_no <= 1'b1;
			else
				checkRr_no <= 1'b0;
		else 
			if(t4 != r)
				checkRr_no <= 1'b1;
			else
				checkRr_no <= 1'b0;
	else
		checkRr_no <= 1'b0;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		sm3_e <= `DATA_WIDTH'd0;
	//else if((state == SM3) && (next_state == ADD_T))
	else if(state == SM3)
		sm3_e <= Hv_r;
	else
		sm3_e <= sm3_e;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		Hv_done_f <= 1'b0;
	else if(Hv_done)
		Hv_done_f <= 1'b1;
	//else if((next_state == FINAL) || (next_state == IDLE))
	else if(next_state == IDLE)
		Hv_done_f <= 1'b0;
	else
		Hv_done_f <= Hv_done_f;
end

/*
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		sha512_done_f <= 1'b0;
	else if(sha512_done)
		sha512_done_f <= 1'b1;
	else if((next_state == FINAL) || (next_state == IDLE))
		sha512_done_f <= 1'b0;
	else
		sha512_done_f <= sha512_done_f;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		sm3_done_f <= 1'b0;
	else if(sm3_done)
		sm3_done_f <= 1'b1;
	else if((next_state == FINAL) || (next_state == IDLE))
		sm3_done_f <= 1'b0;
	else
		sm3_done_f <= sm3_done_f;
end
*/

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		count1 <= 8'd255;
	else if(state == MUL1)
		count1 <= count1 - 1;
	else
		count1 <= 8'd255;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		count2 <= 8'd255;
	else if(state == MUL2)
		count2 <= count2 - 1;
	else
		count2 <= 8'd255;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		INV_enable <= 1'b0;
	else if((state == SHA) && (next_state == INV))
		INV_enable <= 1'b1;
	else if(state_zaddu == 20'b0000_0100_0000_0000_0000)
		INV_enable <= 1'b1;
	else
		INV_enable <= 1'b0;
end

always @(*)
begin
	case(state)
	ADD_T:
	begin
		M_sel_a = 8'b0;
		M_sel_b = 8'b0;
		A_sel_a = 8'b10000010;
		A_sel_b = 8'b10000010;
	end
	ZADDU:
	begin
		M_sel_a = zaddu_M_sel_a;
		M_sel_b = zaddu_M_sel_b;
		A_sel_a = zaddu_A_sel_a;
		A_sel_b = zaddu_A_sel_b;
	end
	ADD_R: 	
	begin
		M_sel_a = 8'b0;
		M_sel_b = 8'b0;
		A_sel_a = 8'b10000100;
		A_sel_b = 8'b00010000;
	end
	default : 	
	begin
		M_sel_a = 8'b0;
		M_sel_b = 8'b0;
		A_sel_a = 8'b0;
		A_sel_b = 8'b0;
	end
	endcase
end

always @(*)
begin
	case(state)
		INV : I_sel = 2'b11;
		ZADDU:I_sel = zaddu_I_sel;
		default : I_sel = 2'b00;
	endcase
end

always @(*)
begin
	case(state)
		ADD_T: r_sel = 22'b000_00_000_000_000_000_001_00;
		SHA : r_sel = 22'b000_00_000_000_000_000_101_00;
		INV : r_sel = 22'b000_00_000_000_111_000_000_00;
		EXCH: r_sel = 22'b000_00_100_101_000_011_110_00;
		ZADDU:r_sel = zaddu_r_sel;
		ADD_R: r_sel = 22'b000_00_000_001_000_000_000_00;
		default : r_sel = 22'b0;
	endcase
end

assign n = (curve_sel == 1'b0) ? `n_256r1 : `n_sm2;

assign kk1 = (t3[count1] == 1) ? t1 : 0;
assign kk2 = (k1 << 1) + kk1;
assign kk3 = (kk2 >= {2'b00,n}) ? kk2 - n : kk2;

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		k1 <= `DATA_WIDTH'd0;
	//else if((state == IDLE)&&(next_state == CHECK_r))
	else if(next_state == CHECK_r)
		k1 <= `DATA_WIDTH'd0;
	//else if((state == MUL1) && (kk3 >= {2'b00,n}))
	else if(state == MUL1)
		if(kk3 >= {2'b00,n})
			k1 <= kk3 - n;
	//else if((state == MUL1) && (kk3 < {2'b00,n}))
		else
			k1 <= kk3;
	else if((state == KG) && (next_state == KP))
		k1 <= t3;
	else if((state == CHECK_T) && (next_state == KG))
		k1 <= s;
	else
		k1 <= k1;
end

assign kk4 = (t3[count2] == 1) ? r : 0;
assign kk5 = (k2 << 1) + kk4;
assign kk6 = (kk5 >= {2'b00,n}) ? kk5 - n : kk5;

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		k2 <= `DATA_WIDTH'd0;
	else if(next_state == CHECK_r)
		k2 <= `DATA_WIDTH'd0;
	//else if((state == MUL2) && (kk6 >= {2'b00,n}))
	else if(state == MUL2)
		if(kk6 >= {2'b00,n})
			k2 <= kk6 - n;
	//else if((state == MUL2) && (kk6 < {2'b00,n}))
		else
			k2 <= kk6;
	else if((state == CHECK_T) && (next_state == KG))
		k2 <= t1;
	else
		k2 <= k2;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		kg_y <= `DATA_WIDTH'd0;
	else if((state == KG) && (next_state == KP))
		kg_y <= t7;
	else
		kg_y <= kg_y;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		ZADDU_enable <= 1'b0;
	//else if((state == EXCH) && (next_state == ZADDU))
	else if(state == EXCH)
		ZADDU_enable <= 1'b1;
	else
		ZADDU_enable <= 1'b0;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		ML_enable <= 1'b0;
	else if(((state == MUL2) && (next_state == KG)) || ((state == KG) && (next_state == KP)) || ((state == CHECK_T) && (next_state == KG)))
		ML_enable <= 1'b1;
	else
		ML_enable <= 1'b0;
end

assign rr = (t4 >= n) ? t4 - n : t4;

ZADDU zaddu(.clk(clk),
				.rst_n(rst_n),
				.enable(ZADDU_enable),
				.MM_end_flag(MM_end_flag),
				.INV_end_flag(INV_end_flag),
				.MM_enable(MM_enable),
				.func(func),
				.r_sel(zaddu_r_sel),
				.M_sel_a(zaddu_M_sel_a),
				.M_sel_b(zaddu_M_sel_b),
				.A_sel_a(zaddu_A_sel_a),
				.A_sel_b(zaddu_A_sel_b),
				.I_sel(zaddu_I_sel),
				.end_flag(ZADDU_end_flag),
				.state(state_zaddu)
				);
/*
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		bingo<=1'b0;
	end
	else if((state == CHECKRr) && (next_state == FINAL))
	begin
		bingo<=1'b1;
	end
	else
	begin
		bingo<=1'b0;
	end
end
*/
/*
always @(posedge clk or negedge rst_n)
begin
	if(rst_n==1'b0)
	begin
		invalid<=1'b0;
	end
	else if(((state == CHECK_r) && (next_state==IDLE))||((state == CHECK_s) && (next_state==IDLE))||((state == CHECK_P) && (next_state==IDLE))||((state == CHECKRr) && (next_state==IDLE)))
	begin
		invalid<=1'b1;
	end
	else
	begin
		invalid<=1'b0;
	end
end
*/
/*
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		end_flag <= 1'b0;
	else if((state == CHECKRr) || ((state == CHECK_r) && (next_state==IDLE))||((state == CHECK_s) && (next_state==IDLE))||((state == CHECK_P) && (next_state==IDLE))||((state == CHECKRr) && (next_state==IDLE)))
		end_flag <= 1'b1;
	else
		end_flag <= 1'b0;
end
*/

endmodule